package main

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"errors"
	"fmt"
	"io"
	"log"
	"math/rand"
	"mime/multipart"
	"net/http"
	"os"
	"path"
	"reflect"
	"strings"
	"time"
)

var logFile *os.File

func initLogger(name string) error {
	// 创建一个日志文件
	var err error
	logFile, err = os.Create(name)
	if err != nil {
		return err
	}

	log.SetOutput(logFile)
	return nil
}

func generateRandomString(length int) (string, error) {
	// 计算需要生成的随机字节数
	byteLength := (length * 3) / 4 // Base64编码需要的字节数
	if length%4 != 0 {
		byteLength += 3
	}

	// 生成随机字节片
	randomBytes := make([]byte, byteLength)
	_, err := rand.Read(randomBytes)
	if err != nil {
		return "", err
	}

	// 将随机字节片进行Base64编码并截取指定长度的字符串
	randomString := base64.URLEncoding.EncodeToString(randomBytes)[:length]
	return randomString, nil
}

// 文件下载
// 方式一：form表单上传，需填写formFile,head,uploadPath,dir
// 方式二：form表单上传，需填写formFile,head为nil
func downloadFile(formFile multipart.File, head *multipart.FileHeader, url, uploadPath, dir string) (string, error) {
	var (
		src      io.Reader
		fileName string
	)
	if formFile == nil {
		// 发起 HTTP GET 请求来获取文件图片
		resp, err := http.Get(url)
		if err != nil {
			fmt.Println("get file err:", err)
			return "", err
		}
		src = resp.Body
		defer resp.Body.Close()
		fileName = fmt.Sprint(time.Now().UnixNano()) + path.Ext(resp.Request.URL.Path)
	} else {
		src = formFile
		files := strings.Split(head.Filename, ".")
		fileName = fmt.Sprint(time.Now().UnixNano()) + "." + files[len(files)-1]
	}
	uploadFilePath := uploadPath + dir + "/"

	// 创建文件夹
	os.Mkdir(dir, os.ModePerm)

	// 创建目标文件
	file, err := os.Create(uploadFilePath + fileName)
	if err != nil {
		fmt.Println("create file err:", err)
		return "", err
	}
	defer file.Close()

	// 将 HTTP 响应的图片数据写入文件
	_, err = io.Copy(file, src)
	if err != nil {
		fmt.Println("write file err:", err)
		return "", err
	}
	return dir + "/" + fileName, nil
}

func GetMD5Upper(s string) string {
	return strings.ToUpper(GetMD5(s))
}

// aes加密
func AesEncrypt(key, iv, plaindata []byte) ([]byte, error) {
	if len(key) != 16 {
		return nil, errors.New("invalid decrypt key")
	}
	if len(iv) != 16 {
		return nil, errors.New("invalid decrypt iv")
	}
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, errors.New("invalid decrypt key")
	}
	data := PKCS5Padding(plaindata, aes.BlockSize)
	cipherdata := make([]byte, len(data))
	cipher.NewCBCEncrypter(block, iv).CryptBlocks(cipherdata, data)

	return cipherdata, nil
}

func PKCS5Padding(data []byte, blockSize int) []byte {
	padding := blockSize - len(data)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(data, padtext...)
}

func Map2Struct(m map[string]interface{}, tagName string, obj interface{}) {

	t := reflect.TypeOf(obj)
	v := reflect.ValueOf(obj)

	if t.Kind() != reflect.Ptr {
		return
	}

	t = t.Elem()
	if t.Kind() != reflect.Struct {
		return
	}

	v = v.Elem()

	var (
		data = make(map[string]interface{})
	)

	for i := 0; i < t.NumField(); i++ {
		var (
			fd = t.Field(i)
			vd = v.Field(i)
		)

		keyName := fd.Tag.Get(tagName)
		if keyName == "" || keyName == "-" {
			continue
		}
		if _, ok := m[keyName]; !ok {
			continue
		}
		if vd.CanSet() {
			vd.Set(reflect.ValueOf(m[keyName]))
		}

		data[keyName] = v.Field(i).Interface()
	}
	return
}
